package com.intretech.tj.etc;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.intretech.tj.device.DeviceVerticle;
import com.intretech.tj.device.MessageData;
import com.intretech.tj.device.Type;
import com.intretech.tj.global.exception.IPErrorException;
import com.intretech.tj.mqtt.MQTTVerticle;
import com.intretech.tj.mqtt.trigger.TopicMessageTrigger;
import com.intretech.tj.tcp.TCPVerticle;
import io.smallrye.mutiny.vertx.core.AbstractVerticle;
import io.vertx.core.Promise;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.IntStream;

import static com.intretech.tj.etc.OutLog.*;
import static com.intretech.tj.global.tools.HexTool.decimalToHexStr;
import static com.intretech.tj.global.tools.JSONTool.toJSONString;
import static com.intretech.tj.global.tools.TimeTool.getNowTime;

@Slf4j
@ApplicationScoped
public class ETCVerticle extends AbstractVerticle {
    private final OutLog outLog;
    private final ETCConfig config;

    private final TopicMessageTrigger topicMessageTrigger;
    private final TCPVerticle tcpVerticle;
    private final DeviceVerticle deviceVerticle;
    private final MQTTVerticle mqttVerticle;

    List<ETC> etcList = new CopyOnWriteArrayList<>();

    @Inject
    public ETCVerticle(OutLog outLog, ETCConfig config, TopicMessageTrigger topicMessageTrigger, TCPVerticle tcpVerticle, DeviceVerticle deviceVerticle, MQTTVerticle mqttVerticle) {
        this.outLog = outLog;
        this.config = config;
        this.topicMessageTrigger = topicMessageTrigger;
        this.tcpVerticle = tcpVerticle;
        this.deviceVerticle = deviceVerticle;
        this.mqttVerticle = mqttVerticle;
    }

    @Override
    public void start(Promise<Void> startPromise) {
        if (config.enable()) {
            etcList.addAll(IntStream.range(1, config.maximum() + 1)
                    .mapToObj(ETC::new)
                    .toList());
            etcList.forEach(etc -> deviceVerticle.update(etc.toDevice()));
            topicMessageTrigger.setTrigger(config.topic(), outLog.getServerName(), (idAndMessage) -> {
                ObjectMapper objectMapper = new ObjectMapper();
                try {
                    ETC etc = objectMapper.readValue(idAndMessage.message().payload().toString(), ETC.class);
                    String msg = config.message().formatted(
                            decimalToHexStr(etc.getId()),
                            decimalToHexStr(etc.getState().getValue()));
                    try {
                        tcpVerticle.send(config.address(), msg);
                        mqttVerticle.publish(config.event(), 0, toJSONString(new MessageData(String.valueOf(etc.getId()), Type.Gate, etc.getState().getChinese(), getNowTime())));
                    } catch (IPErrorException e) {
                        mqttVerticle.publish(config.error(), 0, toJSONString(new MessageData(String.valueOf(etc.getId()), Type.Gate, Error, getNowTime())));
                    }
                    deviceVerticle.update(etc.toDevice());
                    log.info(outLog.getMessage(Update, etc.getId(), etc.getState().getChinese(), msg));
                } catch (JsonProcessingException e) {
                    log.error(outLog.getMessage(JSONError));
                }
            });
        }
    }
}
